// ============================================================================
// File: pkg/recovery/recovery.go - Crash Recovery
// ============================================================================
package recovery

import (
	"database/sql"
	"fmt"
	"os"
	"path/filepath"

	"github.com/sirupsen/logrus"
	_ "github.com/mattn/go-sqlite3"
)

func RecoverSnapshots(root string) error {
	logrus.Info("attempting to recover snapshots from previous session")

	dbPath := filepath.Join(root, "metadata.db")
	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
		logrus.Info("no previous metadata found, starting fresh")
		return nil
	}

	db, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		return fmt.Errorf("failed to open metadata db: %w", err)
	}
	defer db.Close()

	// Check database integrity
	var integrityCheck string
	err = db.QueryRow("PRAGMA integrity_check").Scan(&integrityCheck)
	if err != nil {
		return fmt.Errorf("failed integrity check: %w", err)
	}

	if integrityCheck != "ok" {
		logrus.Warn("database integrity check failed, rebuilding")
		return rebuildDatabase(root)
	}

	// Count existing snapshots
	var count int
	err = db.QueryRow("SELECT COUNT(*) FROM snapshots").Scan(&count)
	if err != nil {
		return fmt.Errorf("failed to count snapshots: %w", err)
	}

	logrus.Infof("recovered %d snapshots from previous session", count)

	// Verify snapshot directories exist
	rows, err := db.Query("SELECT id, name FROM snapshots")
	if err != nil {
		return err
	}
	defer rows.Close()

	orphaned := 0
	for rows.Next() {
		var id, name string
		if err := rows.Scan(&id, &name); err != nil {
			continue
		}

		snapDir := filepath.Join(root, "snapshots", id)
		if _, err := os.Stat(snapDir); os.IsNotExist(err) {
			logrus.Warnf("snapshot %s (%s) directory missing, marking as orphaned", name, id)
			orphaned++
		}
	}

	if orphaned > 0 {
		logrus.Warnf("found %d orphaned snapshots", orphaned)
	}

	return nil
}

func rebuildDatabase(root string) error {
	logrus.Info("rebuilding metadata database from filesystem")

	// Backup old database
	oldDb := filepath.Join(root, "metadata.db")
	backupDb := filepath.Join(root, "metadata.db.backup")
	if err := os.Rename(oldDb, backupDb); err != nil {
		logrus.WithError(err).Warn("failed to backup old database")
	}

	// Create new database
	db, err := sql.Open("sqlite3", oldDb)
	if err != nil {
		return err
	}
	defer db.Close()

	// Create schema
	schema := `
	CREATE TABLE snapshots (
		id TEXT PRIMARY KEY,
		name TEXT UNIQUE,
		parent TEXT,
		kind INTEGER,
		created_at INTEGER,
		updated_at INTEGER,
		size INTEGER,
		inodes INTEGER,
		labels TEXT
	);
	CREATE INDEX idx_name ON snapshots(name);
	CREATE INDEX idx_parent ON snapshots(parent);
	`

	if _, err := db.Exec(schema); err != nil {
		return fmt.Errorf("failed to create schema: %w", err)
	}

	// Scan filesystem and rebuild entries
	snapshotsDir := filepath.Join(root, "snapshots")
	entries, err := os.ReadDir(snapshotsDir)
	if err != nil {
		return err
	}

	for _, entry := range entries {
		if !entry.IsDir() {
			continue
		}

		id := entry.Name()
		// Insert with minimal information
		_, err := db.Exec(`
			INSERT INTO snapshots (id, name, parent, kind, created_at, updated_at, size, inodes, labels)
			VALUES (?, ?, '', 0, 0, 0, 0, 0, '')
		`, id, id)
		
		if err != nil {
			logrus.WithError(err).Warnf("failed to insert snapshot %s", id)
		}
	}

	logrus.Info("database rebuild complete")
	return nil
}
